package com.ccrfid.rmc6.lbservice3.mq;

import com.ccrfid.rmc6.entity.device.CardActiveView;
import com.ccrfid.rmc6.entity.device.CardEntity;
import com.ccrfid.rmc6.entity.device.LocatorEntity;
import com.ccrfid.rmc6.lbservice3.pojo.locate.AssetLocateInfo;
import com.ccrfid.rmc6.lbservice3.pojo.locate.PersonnelLocateInfo;
import com.ccrfid.rmc6.lbservice3.pojo.msg.*;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.service.device.CardService;
import com.ccrfid.rmc6.service.device.LocatorService;
import com.ccrfid.rmc6.util.GeomUtil;
import com.google.common.eventbus.EventBus;
import com.vividsolutions.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Component
public class MsgDispatcher {
    private static final Logger logger = LoggerFactory.getLogger(MsgDispatcher.class);
    private boolean isRunning;
    private BlockingQueue<MqMsgDev> msgDevQueue;
    private BlockingQueue<MqMsgDev> msgDevLocateQueue;
    private BlockingQueue<MqPersonnelAlarm> personnelAlarmQueue;
    private BlockingQueue<MqLocationAlarm> locationAlarmQueue;
    private BlockingQueue<MqPersonnelGroupAlarm> personnelGroupAlarmQueue;
    private BlockingQueue<MqTagPosition> msgTagPositionQueue;
    private BlockingQueue<MqTagStatus> msgTagStatusQueue;
    private ExecutorService executorService;
    private Map<Long, CardTraceInfo> cardTraceMap;

    @Value("${time.interval.locate}")
    private Integer timeIntervalLocate;
    @Value("${time.interval.active}")
    private Integer timeIntervalActive;
    @Value("${time.interval.cut}")
    private Integer timeIntervalCut;
    @Value("${time.interval.keepalive}")
    private Integer timeIntervalKeepalive;
    @Value("${time.interval.heartRate}")
    private Integer timeIntervalHeartRate;
    @Value("${time.interval.battery}")
    private Integer timeIntervalBattery;
    @Value("${time.interval.temperature}")
    private Integer timeIntervalTemperature;
    @Value("${time.interval.bloodPressure}")
    private Integer timeIntervalBloodPressure;
    @Value("${time.interval.stepTrack}")
    private Integer timeIntervalStepTrack;
    @Value("${recv.buf.length}")
    private Integer lengthBase;
    @Value("${coordinate.mixed}")
    private boolean coordinateMixed;
    @Value("${in-active-status.timeout}")
    private Integer inActiveStatusTimeout;

    @Autowired
    private EventBus eventBus;
    @Autowired
    private CardService cardService;
    @Autowired
    private LocatorService locatorService;

    public MsgDispatcher() {
        this.isRunning = true;
        this.executorService = Executors.newFixedThreadPool(10);
        this.cardTraceMap = new ConcurrentHashMap<>();
    }

    @PostConstruct
    private void init() {
        this.msgDevQueue = new LinkedBlockingDeque<>(1024 * (lengthBase > 8 ? lengthBase : 8));
        this.msgDevLocateQueue = new LinkedBlockingDeque<>(1024 * (lengthBase > 8 ? lengthBase : 8));
        this.msgTagPositionQueue = new LinkedBlockingDeque<>(1024 * (lengthBase > 8 ? lengthBase : 8));
        this.msgTagStatusQueue = new LinkedBlockingDeque<>(1024 * (lengthBase > 8 ? lengthBase : 8));
        this.personnelAlarmQueue = new LinkedBlockingDeque<>(512 * (lengthBase > 8 ? lengthBase : 8));
        this.locationAlarmQueue = new LinkedBlockingDeque<>(512 * (lengthBase > 8 ? lengthBase : 8));
        this.personnelGroupAlarmQueue = new LinkedBlockingDeque<>(512 * (lengthBase > 8 ? lengthBase : 8));
        //1.初始化标签当前位置信息
        initCardTraceMap();

        //线程1：解析人员告警消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("personnelAlarmQueue size: {}", personnelAlarmQueue.size());
                        }
                        MqPersonnelAlarm personnelAlarm = personnelAlarmQueue.take();
                        decodeData(personnelAlarm);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程2：解析区域告警消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("locationAlarmQueue size: {}", locationAlarmQueue.size());
                        }
                        MqLocationAlarm locationAlarm = locationAlarmQueue.take();
                        decodeData(locationAlarm);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程3：解析设备消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("msgDevQueue size: {}", msgDevQueue.size());
                        }
                        MqMsgDev msgDev = msgDevQueue.take();
                        decodeData(msgDev);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程4：解析设备定位消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("msgDevLocateQueue size: {}", msgDevLocateQueue.size());
                        }
                        MqMsgDev msgDev = msgDevLocateQueue.take();
                        decodeLocateData(msgDev);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程5: 解析精确定位标签位置消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("msgTagPositionQueue size: {}", msgTagPositionQueue.size());
                        }
                        MqTagPosition mqTagPosition = msgTagPositionQueue.take();
                        decodeData(mqTagPosition);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程6: 解析精确定位标签状态消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("msgTagStatusQueue size: {}", msgTagStatusQueue.size());
                        }
                        MqTagStatus mqTagStatus = msgTagStatusQueue.take();
                        decodeData(mqTagStatus);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程7: 解析人员分组告警消息
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        if (logger.isTraceEnabled()) {
                            logger.trace("personnelGroupAlarmQueue size: {}", personnelGroupAlarmQueue.size());
                        }
                        MqPersonnelGroupAlarm groupAlarm = personnelGroupAlarmQueue.take();
                        decodeData(groupAlarm);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        //线程8: 激活状态超时复位
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(5000);
                        cardTraceMap.forEach((key, value) -> {
                            if (value.isInActiveLocator()
                                    && (System.currentTimeMillis() - value.getTimeInActiveLocator() > inActiveStatusTimeout)) {
                                value.setInActiveLocator(false);
                                logger.trace("setInActiveLocator: false, card: {}:{}, in-active status timeout",
                                        value.getCardNumber(), Long.toHexString(value.getCardNumber()));
                            }
                        });
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });
    }

    public boolean inputData(MqMsgDev msgDev) {
        if (logger.isTraceEnabled()) {
            logger.trace("input msgDevQueue size: {}", msgDevQueue.size());
        }
        return msgDevQueue.offer(msgDev);
    }

    public boolean inputLocateData(MqMsgDev msgDev) {
        if (logger.isTraceEnabled()) {
            logger.trace("input msgDevLocateQueue size: {}", msgDevLocateQueue.size());
        }
        return msgDevLocateQueue.offer(msgDev);
    }

    public boolean inputData(MqTagPosition mqTagPosition) {
        if (logger.isTraceEnabled()) {
            logger.trace("input msgTagPositionQueue size: {}", msgTagPositionQueue.size());
        }
        return msgTagPositionQueue.offer(mqTagPosition);
    }

    public boolean inputData(MqTagStatus mqTagStatus) {
        if (logger.isTraceEnabled()) {
            logger.trace("input msgTagStatusQueue size: {}", msgTagStatusQueue.size());
        }
        return msgTagStatusQueue.offer(mqTagStatus);
    }

    public boolean inputData(MqPersonnelAlarm personnelAlarm) {
        if (logger.isTraceEnabled()) {
            logger.trace("input personnelAlarmQueue size: {}", personnelAlarmQueue.size());
        }
        return personnelAlarmQueue.offer(personnelAlarm);
    }

    public boolean inputData(MqLocationAlarm locationAlarm) {
        if (logger.isTraceEnabled()) {
            logger.trace("input locationAlarmQueue size: {}", locationAlarmQueue.size());
        }
        return locationAlarmQueue.offer(locationAlarm);
    }

    public boolean inputData(MqPersonnelGroupAlarm groupAlarm) {
        if (logger.isTraceEnabled()) {
            logger.trace("input personnelGroupAlarmQueue size: {}", personnelGroupAlarmQueue.size());
        }
        return personnelGroupAlarmQueue.offer(groupAlarm);
    }

    //标签人员绑定，模拟发送当前定位信息
    @Caching(
            evict = {
                    @CacheEvict(value = "personnels", key = "#cardNumber"),
                    @CacheEvict(value = "personnels2", key = "#personnelId")
            })
    public void bindPersonnelCard(Long personnelId, Long cardNumber) {
        CardTraceInfo traceInfo = cardTraceMap.get(cardNumber);
        if (traceInfo != null) {
            MsgLocate msgLocate = new MsgLocate(traceInfo.getCardType(), cardNumber, traceInfo.getLocatorNumber(),
                    traceInfo.getPos(), traceInfo.getFloorNumber(), traceInfo.getTimeLocate());

            PersonnelLocateInfo locateInfo = new PersonnelLocateInfo(personnelId, msgLocate);
            eventBus.post(locateInfo);
        }
    }

    //标签人员解除绑定，模拟离开信息
    @Caching(
            evict = {
                    @CacheEvict(value = "personnels", key = "#cardNumber"),
                    @CacheEvict(value = "personnels2", key = "#personnelId")
            })
    public void unBindPersonnelCard(Long personnelId, Long cardNumber) {
        CardTraceInfo traceInfo = cardTraceMap.get(cardNumber);
        if (traceInfo != null) {
            MsgLocate msgLocate = new MsgLocate(cardNumber, new Date().getTime());
            msgLocate.setCardType(traceInfo.getCardType());
            msgLocate.setFrontLocator(traceInfo.getLocatorNumber());
            msgLocate.setFrontPos(traceInfo.getPos());
            msgLocate.setFrontFloorNumber(traceInfo.getFloorNumber());

            PersonnelLocateInfo locateInfo = new PersonnelLocateInfo(personnelId, msgLocate);
            eventBus.post(locateInfo);
        }
    }

    //标签-资产绑定，模拟发送当前定位信息
    public void bindAssetCard(Long assetId, Long cardNumber) {
        CardTraceInfo traceInfo = cardTraceMap.get(cardNumber);
        if (traceInfo != null) {
            MsgLocate msgLocate = new MsgLocate(traceInfo.getCardType(), cardNumber, traceInfo.getLocatorNumber(),
                    traceInfo.getPos(), traceInfo.getFloorNumber(), traceInfo.getTimeLocate());

            AssetLocateInfo locateInfo = new AssetLocateInfo(assetId, msgLocate);
            eventBus.post(locateInfo);
        }
    }

    //标签-资产解除绑定，模拟离开信息
    public void unBindAssetCard(Long assetId, Long cardNumber) {
        CardTraceInfo traceInfo = cardTraceMap.get(cardNumber);
        if (traceInfo != null) {
            MsgLocate msgLocate = new MsgLocate(cardNumber, new Date().getTime());
            msgLocate.setCardType(traceInfo.getCardType());
            msgLocate.setFrontLocator(traceInfo.getLocatorNumber());
            msgLocate.setFrontPos(traceInfo.getPos());
            msgLocate.setFrontFloorNumber(traceInfo.getFloorNumber());

            AssetLocateInfo locateInfo = new AssetLocateInfo(assetId, msgLocate);
            eventBus.post(locateInfo);
        }
    }

    private void initCardTraceMap() {
        List<CardEntity> cardEntities = cardService.getAllCards();
        for (CardEntity cardEntity : cardEntities) {
            CardTraceInfo traceInfo = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
            traceInfo.setLowpowerStatus(cardEntity.getLowpowerStatus());
            traceInfo.setCutoffStatus(cardEntity.getCutoffStatus());
            if (cardEntity.getCardNumber() != null) {
                cardTraceMap.put(cardEntity.getCardNumber(), traceInfo);
            }
        }

        List<CardActiveView> cardActiveEntities = cardService.getAllCardActives();
        for (CardActiveView activeEntity : cardActiveEntities) {
            CardTraceInfo traceInfo = cardTraceMap.get(activeEntity.getCardNumber());
            if (traceInfo != null) {
                traceInfo.setFloorNumber(activeEntity.getFloorNumber());
                traceInfo.setLocatorNumber(activeEntity.getLocatorAddress());
                traceInfo.setPos(activeEntity.getPos());
                traceInfo.setTimeLocate(activeEntity.getUpdateTime().getTime());
            } else {
                CardEntity cardEntity = cardService.getCardByCardNumber(activeEntity.getCardNumber());
                if (cardEntity != null) {
                    traceInfo = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                    traceInfo.setLowpowerStatus(cardEntity.getLowpowerStatus());
                    traceInfo.setCutoffStatus(cardEntity.getCutoffStatus());
                    traceInfo.setFloorNumber(activeEntity.getFloorNumber());
                    traceInfo.setLocatorNumber(activeEntity.getLocatorAddress());
                    traceInfo.setPos(activeEntity.getPos());
                    traceInfo.setTimeLocate(activeEntity.getUpdateTime().getTime());
                    if (cardEntity.getCardNumber() != null) {
                        cardTraceMap.put(cardEntity.getCardNumber(), traceInfo);
                    }
                }
            }
        }
    }

    private void decodeData(MqPersonnelAlarm personnelAlarm) {
        long startTime = System.currentTimeMillis();
        eventBus.post(personnelAlarm);
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decode MqPersonnelAlarm cost: {} ms, alarm: {}", stopTime - startTime, personnelAlarm);
        }
    }

    private void decodeData(MqLocationAlarm locationAlarm) {
        long startTime = System.currentTimeMillis();
        eventBus.post(locationAlarm);
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decode MqLocationAlarm cost: {} ms, locationAlarm: {}", stopTime - startTime, locationAlarm);
        }
    }

    private void decodeData(MqPersonnelGroupAlarm groupAlarm) {
        long startTime = System.currentTimeMillis();
        eventBus.post(groupAlarm);
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decode MqPersonnelGroupAlarm cost: {} ms, groupAlarm: {}", stopTime - startTime, groupAlarm);
        }
    }

    private void decodeData(MqTagPosition mqTagPosition) {
        long startTime = System.currentTimeMillis();
        CardEntity cardEntity = cardService.getCardByHexNumber(mqTagPosition.getTag().toUpperCase());
        if (cardEntity != null) {
            CardTraceInfo traceInfo = cardTraceMap.get(cardEntity.getCardNumber());
            if (coordinateMixed) {
                if (traceInfo != null && traceInfo.isInActiveLocator()) {
                    //混合使用RFID定位和精确定位的情况下，标签在激活区则忽略精确定位信号
                    logger.trace("ignore tag position, card {}:{} is inActiveLocator",
                            mqTagPosition.getTag(), cardEntity.getCardNumber());
                    return;
                }
            }

            MsgLocateActive msgLocateActive = new MsgLocateActive(cardEntity.getCardNumber(), mqTagPosition.getT());
            msgLocateActive.setCurrentLocator(0);
            msgLocateActive.setX(mqTagPosition.getX());
            msgLocateActive.setY(mqTagPosition.getY());
            msgLocateActive.setAccuracy(mqTagPosition.getPa());
            msgLocateActive.setCurrentFloorNumber(mqTagPosition.getF());
            //post msgLocateActive
            logger.trace("post tag msgLocateActive: {}", msgLocateActive);
            eventBus.post(msgLocateActive);

            MsgLocate msgLocate = new MsgLocate(cardEntity.getCardNumber(), mqTagPosition.getT());
            msgLocate.setCardType(cardEntity.getCardType());
            msgLocate.setCurrentLocator(0);
            msgLocate.setCurrentPos(GeomUtil.INSTANCE.createPoint(mqTagPosition.getX(), mqTagPosition.getY()));
            msgLocate.setCurrentFloorNumber(mqTagPosition.getF());

            if (traceInfo != null) {
                msgLocate.setFrontLocator(traceInfo.getLocatorNumber());
                msgLocate.setFrontPos(traceInfo.getPos());
                msgLocate.setFrontFloorNumber(traceInfo.getFloorNumber());
                //update traceInfo
                traceInfo.setLocatorNumber(0);
                traceInfo.setPos(msgLocate.getCurrentPos());
                traceInfo.setFloorNumber(msgLocate.getCurrentFloorNumber());
                traceInfo.setTimeLocate(msgLocate.getTime());
                traceInfo.setTimeLocateActive(msgLocateActive.getTime());
                //post msgLocate
                logger.trace("post tag msgLocate: {}", msgLocate);
                eventBus.post(msgLocate);
            } else {
                //初次定位
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setLocatorNumber(msgLocate.getCurrentLocator());
                info.setPos(msgLocate.getCurrentPos());
                info.setFloorNumber(msgLocate.getCurrentFloorNumber());
                info.setTimeLocate(msgLocate.getTime());
                info.setTimeLocateActive(msgLocate.getTime());
                cardTraceMap.put(msgLocate.getCardNumber(), info);
                //post msgLocate
                logger.trace("first message, post tag msgLocate: {}", msgLocate);
                eventBus.post(msgLocate);
            }
        }
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decodeData cost: {} ms, tag: {}", stopTime - startTime, mqTagPosition.getTag());
        }
    }

    private void decodeData(MqTagStatus mqTagStatus) {
        long startTime = System.currentTimeMillis();
        CardEntity cardEntity = cardService.getCardByHexNumber(mqTagStatus.getTag().toUpperCase());
        if (cardEntity != null) {
            //0.获取缓存状态
            CardTraceInfo traceInfo = cardTraceMap.get(cardEntity.getCardNumber());
            if (traceInfo == null) {
                traceInfo = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                cardTraceMap.put(cardEntity.getCardNumber(), traceInfo);
            }
            //1.电量
            if (mqTagStatus.getBat() != null && mqTagStatus.getT() - traceInfo.getTimeBattery() > timeIntervalBattery) {
                traceInfo.setTimeBattery(mqTagStatus.getT());
                MsgPowerCheck msgPowerCheck = new MsgPowerCheck(cardEntity.getCardNumber(), mqTagStatus.getBat(), mqTagStatus.getT());
                logger.trace("post msgPowerCheck: {}", msgPowerCheck);
                eventBus.post(msgPowerCheck);
            }
            //2.心率
            //200以下表示正常心率
            if (mqTagStatus.getHr() != null && mqTagStatus.getHr().intValue() < 200
                    && mqTagStatus.getT() - traceInfo.getTimeHeartRate() > timeIntervalHeartRate) {
                traceInfo.setTimeHeartRate(mqTagStatus.getT());
                MsgHeartRate msgHeartRate = new MsgHeartRate(cardEntity.getCardNumber(), mqTagStatus.getHr(),
                        mqTagStatus.getT2() != null ? mqTagStatus.getT2() : mqTagStatus.getT());
                logger.trace("decodeData(MqTagStatus) post msgHeartRate: {}", msgHeartRate);
                eventBus.post(msgHeartRate);
            }
            //3.低电状态
            if (mqTagStatus.getLo() != null && !mqTagStatus.getLo().equals(traceInfo.getLowpowerStatus())) {
                MsgLowpowerStatus msgLowpowerStatus =
                        new MsgLowpowerStatus(cardEntity.getCardNumber(), mqTagStatus.getLo(), mqTagStatus.getT());
                traceInfo.setLowpowerStatus(mqTagStatus.getLo());
                logger.trace("post msgLowpowerStatus: {}", msgLowpowerStatus);
                eventBus.post(msgLowpowerStatus);
            }
            //4.剪断状态
            if (mqTagStatus.getCt() != null
                    && (!mqTagStatus.getCt().equals(traceInfo.getCutoffStatus())
                    || mqTagStatus.getT() - traceInfo.getTimeCut() > timeIntervalCut)) {
                MsgCut msgCut = new MsgCut(cardEntity.getCardNumber(), mqTagStatus.getCt(), mqTagStatus.getT());
                traceInfo.setTimeCut(mqTagStatus.getT());
                traceInfo.setCutoffStatus(mqTagStatus.getCt());
                logger.trace("post msgCut: {}", msgCut);
                eventBus.post(msgCut);
            }
            //5.呼叫/按钮
            if (mqTagStatus.getBtn() != null && mqTagStatus.getBtn().equals(1)) {
                MsgCall msgCall = new MsgCall(cardEntity.getCardNumber(), mqTagStatus.getT());
                logger.trace("post msgCall: {}", msgCall);
                eventBus.post(msgCall);
            }

            //6.血压 //250一下正常血压
            if (mqTagStatus.getDp() != null && mqTagStatus.getSp() != null && mqTagStatus.getDp().intValue() < 250 && mqTagStatus.getSp().intValue() < 250
                    && mqTagStatus.getDp() > 0 && mqTagStatus.getSp() > 0) {
                MsgBloodPressure msgBloodPressure = new MsgBloodPressure(cardEntity.getCardNumber(),
                        mqTagStatus.getDp(), mqTagStatus.getSp(), mqTagStatus.getT2());
                if (msgBloodPressure.getTime() - traceInfo.getTimeBloodPressure() > timeIntervalBloodPressure) {
                    traceInfo.setTimeBloodPressure(msgBloodPressure.getTime());
                    logger.trace("decodeData(MqTagStatus) post msgBloodPressure: {}", msgBloodPressure);
                    eventBus.post(msgBloodPressure);
                } else {
                    logger.trace("ignore msgBloodPressure: {}", msgBloodPressure);
                }
            }

            //7.体温
            if (mqTagStatus.getTp() != null && mqTagStatus.getTp() > 0 && mqTagStatus.getT3() != null) {
                MsgTemperature msgTemperature = new MsgTemperature(cardEntity.getCardNumber(), mqTagStatus.getTp(),
                        mqTagStatus.getT3());
                if (msgTemperature.getTime() - traceInfo.getTimeTemperature() > timeIntervalTemperature) {
                    traceInfo.setTimeTemperature(msgTemperature.getTime());
                    logger.trace("post msgTemperature: {}", msgTemperature);
                    eventBus.post(msgTemperature);
                } else {
                    logger.trace("ignore msgTemperature: {}", msgTemperature);
                }
            }

            //8.计步
            if (mqTagStatus.getStp() != null && mqTagStatus.getStp() > 0 && mqTagStatus.getT3() != null) {
                MsgStepTrack msgStepTrack = new MsgStepTrack(cardEntity.getCardNumber(), mqTagStatus.getStp(),
                        mqTagStatus.getT3());
                if (msgStepTrack.getTime() - traceInfo.getTimeStepTrack() > timeIntervalStepTrack) {
                    traceInfo.setTimeStepTrack(msgStepTrack.getTime());
                    logger.trace("post msgStepTrack: {}", msgStepTrack);
                    eventBus.post(msgStepTrack);
                } else {
                    logger.trace("ignore msgStepTrack: {}", msgStepTrack);
                }
            }

            //6.激活状态
            if (mqTagStatus.getT() != null && mqTagStatus.getT() > traceInfo.getTimeInActiveLocator()) {
                if (mqTagStatus.getIa().equals(1)) {
                    traceInfo.setInActiveLocator(true);
                    traceInfo.setTimeInActiveLocator(mqTagStatus.getT());
                    logger.trace("setInActiveLocator: true, card: {}:{}",
                            traceInfo.getCardNumber(), Long.toHexString(traceInfo.getCardNumber()));
                } else {
                    traceInfo.setInActiveLocator(false);
                    traceInfo.setTimeInActiveLocator(mqTagStatus.getT());
                    logger.trace("setInActiveLocator: false, card: {}:{}",
                            traceInfo.getCardNumber(), Long.toHexString(traceInfo.getCardNumber()));
                }
            }
        }
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decode mqTagStatus cost: {} ms, tagStatus: {}", stopTime - startTime, mqTagStatus);
        }
    }

    private void decodeData(MqMsgDev msgDev) {
        if (logger.isTraceEnabled()) {
            logger.trace("decodeData msgDev: {}", msgDev);
        }
        long startTime = System.currentTimeMillis();
        switch (msgDev.getMsgType()) {
            case MsgType.DEVICE_MESSAGE_TYPE_BEATHEART:
                postMsgKeepalive(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_CUT:
                postMsgCut(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_OFFLINE:
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_ENTERLOCATOR:
//                postMsgEnterLocator(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_LEAVELOCATOR:
//                postMsgLeaveLocator(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_CALL:
                postMsgCall(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_OFFALARM:
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_LOWPWR:
                postMsgLowPowerStatus(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_NORMALPWR:
                postMsgNormalPowerStatus(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_ONLINE:
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_HEARTRATE:
//                postMsgHeartRate(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_POWER:
//                postMsgPowerCheck(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_LOCATE:
//                postMsgLocate(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_STEP:
//                postMsgStepTrack(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_TEMPERATURE:
//                postMsgTemperature(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_BLOOD_PRESSURE:
//                postMsgBloodPressure(msgDev);
                break;
        }
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decodeData cost: {} ms, msgDev: {}", stopTime - startTime, msgDev);
        }
    }

    private void decodeLocateData(MqMsgDev msgDev) {
        if (logger.isTraceEnabled()) {
            logger.trace("decodeLocateData msgDev: {}", msgDev);
        }
        long startTime = System.currentTimeMillis();
        switch (msgDev.getMsgType()) {
            case MsgType.DEVICE_MESSAGE_TYPE_BEATHEART:
//                postMsgKeepalive(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_CUT:
//                postMsgCut(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_OFFLINE:
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_ENTERLOCATOR:
                postMsgEnterLocator(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_LEAVELOCATOR:
                postMsgLeaveLocator(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_CALL:
//                postMsgCall(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_OFFALARM:
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_LOWPWR:
//                postMsgLowPowerStatus(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_NORMALPWR:
//                postMsgNormalPowerStatus(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_ONLINE:
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_HEARTRATE:
                postMsgHeartRate(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_POWER:
                postMsgPowerCheck(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_LOCATE:
                postMsgLocate(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_STEP:
                postMsgStepTrack(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_TEMPERATURE:
                postMsgTemperature(msgDev);
                break;
            case MsgType.DEVICE_MESSAGE_TYPE_BLOOD_PRESSURE:
                postMsgBloodPressure(msgDev);
                break;
        }
        long stopTime = System.currentTimeMillis();
        if (logger.isTraceEnabled()) {
            logger.trace("decodeLocateData cost: {} ms, msgDev: {}", stopTime - startTime, msgDev);
        }
    }

    private void postMsgEnterLocator(MqMsgDev msgDev) {
        logger.trace("postMsgEnterLocator: {}", msgDev);
        LocatorEntity locatorEntity = locatorService.getLocatorByLocatorAddress(msgDev.getLocatorNumber());
        if (locatorEntity != null) {
            //1.进入激活区
            CardTraceInfo traceInfo = cardTraceMap.get(msgDev.getCardNumber());
            if (traceInfo != null) {
                traceInfo.setInActiveLocator(true);
                traceInfo.setTimeInActiveLocator(msgDev.getTime());
                logger.trace("setInActiveLocator: true, card: {}:{}",
                        traceInfo.getCardNumber(), Long.toHexString(traceInfo.getCardNumber()));
            } else {
                CardEntity cardEntity = cardService.getCardByCardNumber(msgDev.getCardNumber());
                if (cardEntity != null) {
                    traceInfo = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                    traceInfo.setInActiveLocator(true);
                    traceInfo.setTimeInActiveLocator(msgDev.getTime());
                    cardTraceMap.put(msgDev.getCardNumber(), traceInfo);
                    logger.trace("setInActiveLocator: true, card: {}:{}",
                            traceInfo.getCardNumber(), Long.toHexString(traceInfo.getCardNumber()));
                }
            }
            //2.推送定位
            postMsgLocate(msgDev);
        }
    }

    private void postMsgLeaveLocator(MqMsgDev msgDev) {
        logger.trace("postMsgLeaveLocator: {}", msgDev);
        LocatorEntity locatorEntity = locatorService.getLocatorByLocatorAddress(msgDev.getLocatorNumber());
        if (locatorEntity != null) {
            //离开激活区
            CardTraceInfo traceInfo = cardTraceMap.get(msgDev.getCardNumber());
            if (traceInfo != null) {
                traceInfo.setInActiveLocator(false);
                traceInfo.setTimeInActiveLocator(msgDev.getTime());
                logger.trace("setInActiveLocator: false, card: {}:{}",
                        traceInfo.getCardNumber(), Long.toHexString(traceInfo.getCardNumber()));
            }
        }
    }

    //定位信号
    private void postMsgLocate(MqMsgDev msgDev) {
        CardTraceInfo traceInfo = cardTraceMap.get(msgDev.getCardNumber());
        if (coordinateMixed) {
            if (traceInfo != null && !traceInfo.isInActiveLocator()) {
                //混合使用RFID定位和精确定位的情况下，标签在非激活区则忽略RFID定位信号
                logger.trace("ignore rfid msgLocate, card {}:0x{} not inActiveLocator",
                        msgDev.getCardNumber(), Long.toHexString(msgDev.getCardNumber()));
                return;
            }
        }
        //1.离开
        if (msgDev.getLocatorNumber() < 0) {
            msgDev.setLocatorNumber(0);
        }
        //2.定位
        LocatorEntity locatorEntity = locatorService.getLocatorByLocatorAddress(msgDev.getLocatorNumber());
        MsgLocate msgLocate = new MsgLocate(msgDev.getCardNumber(), msgDev.getTime());
        msgLocate.setCurrentLocator(msgDev.getLocatorNumber());
        msgLocate.setCurrentPos(locatorEntity != null ? locatorEntity.getPos() : null);
        msgLocate.setCurrentFloorNumber(locatorEntity != null ? locatorEntity.getFloorNumber() : null);

        MsgLocateActive msgLocateActive = new MsgLocateActive(msgDev.getCardNumber(), msgDev.getTime());
        msgLocateActive.setCurrentLocator(msgDev.getLocatorNumber());
        msgLocateActive.setX((locatorEntity != null && locatorEntity.getPos() != null) ? locatorEntity.getPos().getX() : null);
        msgLocateActive.setY((locatorEntity != null && locatorEntity.getPos() != null) ? locatorEntity.getPos().getY() : null);
        msgLocateActive.setCurrentFloorNumber(locatorEntity != null ? locatorEntity.getFloorNumber() : null);

        if (traceInfo != null) {
            msgLocate.setCardType(traceInfo.getCardType());
            msgLocate.setFrontLocator(traceInfo.getLocatorNumber());
            msgLocate.setFrontPos(traceInfo.getPos());
            msgLocate.setFrontFloorNumber(traceInfo.getFloorNumber());

            if (msgLocate.getCurrentLocator().equals(msgLocate.getFrontLocator())) {
                //1.相同定位地址，延时过滤
                if (msgLocate.getTime() - traceInfo.getTimeLocate() > timeIntervalLocate) {
                    traceInfo.setLocatorNumber(msgLocate.getCurrentLocator());
                    traceInfo.setPos(msgLocate.getCurrentPos());
                    traceInfo.setFloorNumber(msgLocate.getCurrentFloorNumber());
                    traceInfo.setTimeLocate(msgLocate.getTime());
                    //post msgLocate
                    logger.trace("post msgLocate: {}", msgLocate);
                    eventBus.post(msgLocate);
                } else {
                    logger.trace("ignore msgLocate: {}", msgLocate);
                }
                //更新手环当前位置状态
                if (msgLocateActive.getTime() - traceInfo.getTimeLocateActive() > timeIntervalActive) {
                    traceInfo.setTimeLocateActive(msgLocateActive.getTime());
                    //post msgLocateActive
                    logger.trace("post msgLocateActive: {}", msgLocateActive);
                    eventBus.post(msgLocateActive);
                } else {
                    logger.trace("ignore msgLocateActive: {}", msgLocateActive);
                }
            } else {
                //2.不同定位地址，及时移动
                traceInfo.setLocatorNumber(msgLocate.getCurrentLocator());
                traceInfo.setPos(msgLocate.getCurrentPos());
                traceInfo.setFloorNumber(msgLocate.getCurrentFloorNumber());
                traceInfo.setTimeLocate(msgLocate.getTime());
                //post msgLocate
                logger.trace("post msgLocate: {}", msgLocate);
                eventBus.post(msgLocate);
                //
                traceInfo.setTimeLocateActive(msgLocateActive.getTime());
                //post msgLocateActive
                logger.trace("post msgLocateActive: {}", msgLocateActive);
                eventBus.post(msgLocateActive);
            }
        } else {
            //3.初次被定位，及时移动
            CardEntity cardEntity = cardService.getCardByCardNumber(msgLocate.getCardNumber());
            if (cardEntity != null) {
                msgLocate.setCardType(cardEntity.getCardType());
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setLocatorNumber(msgLocate.getCurrentLocator());
                info.setPos(msgLocate.getCurrentPos());
                info.setFloorNumber(msgLocate.getCurrentFloorNumber());
                info.setTimeLocate(msgLocate.getTime());
                info.setTimeLocateActive(msgLocateActive.getTime());
                cardTraceMap.put(msgLocate.getCardNumber(), info);
                //post msgLocate
                logger.trace("first message, post msgLocate: {}", msgLocate);
                eventBus.post(msgLocate);
                //post msgLocateActive
                logger.trace("post msgLocateActive: {}", msgLocateActive);
                eventBus.post(msgLocateActive);
            }
        }
    }

    //剪断信号
    private void postMsgCut(MqMsgDev msgDev) {
        Integer cutoffStatus = msgDev.getArg1() != null && msgDev.getArg1().equals(0) ? 1 : 0;    //0->1, 1->0
        MsgCut msgCut = new MsgCut(msgDev.getCardNumber(), cutoffStatus, msgDev.getTime());
        CardTraceInfo traceInfo = cardTraceMap.get(msgCut.getCardNumber());
        if (traceInfo != null) {
            if (!cutoffStatus.equals(traceInfo.getCutoffStatus())) {
                traceInfo.setTimeCut(msgCut.getTime());
                traceInfo.setCutoffStatus(cutoffStatus);
                logger.trace("post msgCut: {}", msgCut);
                eventBus.post(msgCut);
            } else {
                if (msgCut.getTime() - traceInfo.getTimeCut() > timeIntervalCut) {
                    traceInfo.setTimeCut(msgCut.getTime());
                    logger.trace("post2 msgCut: {}", msgCut);
                    eventBus.post(msgCut);
                } else {
                    logger.trace("ignore msgCut: {}", msgCut);
                }
            }
        } else {
            CardEntity cardEntity = cardService.getCardByCardNumber(msgCut.getCardNumber());
            if (cardEntity != null) {
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setTimeCut(msgCut.getTime());
                info.setCutoffStatus(msgCut.getCutoffStatus());
                cardTraceMap.put(msgCut.getCardNumber(), info);
                logger.trace("first message, post msgCut: {}", msgCut);
                eventBus.post(msgCut);
            }
        }
    }

    //保活信号
    private void postMsgKeepalive(MqMsgDev msgDev) {
        MsgKeepalive msgKeepalive = new MsgKeepalive(msgDev.getCardNumber(), msgDev.getTime());
        CardTraceInfo traceInfo = cardTraceMap.get(msgKeepalive.getCardNumber());
        if (traceInfo != null) {
            if (msgKeepalive.getTime() - traceInfo.getTimeKeepalive() > timeIntervalKeepalive) {
                traceInfo.setTimeKeepalive(msgKeepalive.getTime());
                logger.trace("post msgKeepalive: {}", msgKeepalive);
                eventBus.post(msgKeepalive);
            } else {
                logger.trace("ignore msgKeepalive: {}", msgKeepalive);
            }
        } else {
            CardEntity cardEntity = cardService.getCardByCardNumber(msgKeepalive.getCardNumber());
            if (cardEntity != null) {
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setTimeKeepalive(msgKeepalive.getTime());
                cardTraceMap.put(msgKeepalive.getCardNumber(), info);
                logger.trace("first message, post msgKeepalive: {}", msgKeepalive);
                eventBus.post(msgKeepalive);
            }
        }
    }

    //呼叫信号
    private void postMsgCall(MqMsgDev msgDev) {
        MsgCall msgCall = new MsgCall(msgDev.getCardNumber(), msgDev.getTime());
        logger.trace("post msgCall: {}", msgCall);
        eventBus.post(msgCall);
    }

    //心率信号
    private void postMsgHeartRate(MqMsgDev msgDev) {
        MsgHeartRate msgHeartRate = new MsgHeartRate(msgDev.getCardNumber(), msgDev.getArg1(), msgDev.getTime());
        CardTraceInfo traceInfo = cardTraceMap.get(msgHeartRate.getCardNumber());
        //心率小于200,过滤
        if(msgHeartRate.getHeartRate().intValue() < 200){
            if (traceInfo != null) {
                if (msgHeartRate.getTime() - traceInfo.getTimeHeartRate() > timeIntervalHeartRate) {
                    traceInfo.setTimeHeartRate(msgHeartRate.getTime());
                    logger.trace("post msgHeartRate: {}", msgHeartRate);
                    eventBus.post(msgHeartRate);
                } else {
                    logger.trace("ignore msgHeartRate: {}", msgHeartRate);
                }
            } else {
                CardEntity cardEntity = cardService.getCardByCardNumber(msgHeartRate.getCardNumber());
                if (cardEntity != null) {
                    CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                    info.setTimeHeartRate(msgHeartRate.getTime());
                    cardTraceMap.put(msgHeartRate.getCardNumber(), info);
                    logger.trace("first message, post msgHeartRate: {}", msgHeartRate);
                    eventBus.post(msgHeartRate);
                }
            }
        }
    }

    //电量信号
    private void postMsgPowerCheck(MqMsgDev msgDev) {
        double battery = msgDev.getArg1() * 0.02;
        MsgPowerCheck msgPowerCheck = new MsgPowerCheck(msgDev.getCardNumber(), battery, msgDev.getTime());
        logger.trace("post msgPowerCheck: {}", msgPowerCheck);
        eventBus.post(msgPowerCheck);
    }

    //低电状态信号
    private void postMsgLowPowerStatus(MqMsgDev msgDev) {
        MsgLowpowerStatus msgLowpowerStatus =
                new MsgLowpowerStatus(msgDev.getCardNumber(), Constants.LOWPOWER_STATUS.LOWPOWER.id, msgDev.getTime());
        postMsgPowerStatus(msgLowpowerStatus);
    }

    //低电恢复信号
    private void postMsgNormalPowerStatus(MqMsgDev msgDev) {
        MsgLowpowerStatus msgLowpowerStatus =
                new MsgLowpowerStatus(msgDev.getCardNumber(), Constants.LOWPOWER_STATUS.NORMAL.id, msgDev.getTime());
        postMsgPowerStatus(msgLowpowerStatus);
    }

    private void postMsgPowerStatus(MsgLowpowerStatus msgLowpowerStatus) {
        CardTraceInfo traceInfo = cardTraceMap.get(msgLowpowerStatus.getCardNumber());
        if (traceInfo != null) {
            if (!msgLowpowerStatus.getLowpowerStatus().equals(traceInfo.getLowpowerStatus())) {
                traceInfo.setLowpowerStatus(msgLowpowerStatus.getLowpowerStatus());
                logger.trace("post msgLowpowerStatus: {}", msgLowpowerStatus);
                eventBus.post(msgLowpowerStatus);
            } else {
                logger.trace("ignore msgLowpowerStatus: {}", msgLowpowerStatus);
            }
        } else {
            CardEntity cardEntity = cardService.getCardByCardNumber(msgLowpowerStatus.getCardNumber());
            if (cardEntity != null) {
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setLowpowerStatus(msgLowpowerStatus.getLowpowerStatus());
                cardTraceMap.put(msgLowpowerStatus.getCardNumber(), info);
                logger.trace("first message, post msgLowpowerStatus: {}", msgLowpowerStatus);
                eventBus.post(msgLowpowerStatus);
            }
        }
    }

    //计步信号
    private void postMsgStepTrack(MqMsgDev msgDev) {
        MsgStepTrack msgStepTrack = new MsgStepTrack(msgDev.getCardNumber(), msgDev.getArg1(), msgDev.getTime());
        CardTraceInfo traceInfo = cardTraceMap.get(msgStepTrack.getCardNumber());
        if (traceInfo != null) {
            if (msgStepTrack.getTime() - traceInfo.getTimeStepTrack() > timeIntervalStepTrack) {
                traceInfo.setTimeStepTrack(msgStepTrack.getTime());
                logger.trace("post msgStepTrack: {}", msgStepTrack);
                eventBus.post(msgStepTrack);
            } else {
                logger.trace("ignore msgStepTrack: {}", msgStepTrack);
            }
        } else {
            CardEntity cardEntity = cardService.getCardByCardNumber(msgStepTrack.getCardNumber());
            if (cardEntity != null) {
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setTimeStepTrack(msgStepTrack.getTime());
                cardTraceMap.put(msgStepTrack.getCardNumber(), info);
                logger.trace("first message, post msgStepTrack: {}", msgStepTrack);
                eventBus.post(msgStepTrack);
            }
        }
    }

    //体温信号
    private void postMsgTemperature(MqMsgDev msgDev) {
        MsgTemperature msgTemperature = new MsgTemperature(msgDev.getCardNumber(), (double) msgDev.getArg1() / 10, msgDev.getTime());
        CardTraceInfo traceInfo = cardTraceMap.get(msgTemperature.getCardNumber());
        if (traceInfo != null) {
            if (msgTemperature.getTime() - traceInfo.getTimeTemperature() > timeIntervalTemperature) {
                traceInfo.setTimeTemperature(msgTemperature.getTime());
                logger.trace("post msgTemperature: {}", msgTemperature);
                eventBus.post(msgTemperature);
            } else {
                logger.trace("ignore msgTemperature: {}", msgTemperature);
            }
        } else {
            CardEntity cardEntity = cardService.getCardByCardNumber(msgTemperature.getCardNumber());
            if (cardEntity != null) {
                CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                info.setTimeTemperature(msgTemperature.getTime());
                cardTraceMap.put(msgTemperature.getCardNumber(), info);
                logger.trace("first message, post msgTemperature: {}", msgTemperature);
                eventBus.post(msgTemperature);
            }
        }
    }

    //血压信号
    private void postMsgBloodPressure(MqMsgDev msgDev) {
        MsgBloodPressure msgBloodPressure = new MsgBloodPressure(msgDev.getCardNumber(), msgDev.getArg2(), msgDev.getArg1(), msgDev.getTime());
        CardTraceInfo traceInfo = cardTraceMap.get(msgBloodPressure.getCardNumber());
        //过滤舒张压和收缩压小于250
        if(msgBloodPressure.getSystolicPressure().intValue() < 250 && msgBloodPressure.getDiastolicPressure().intValue() < 250){
            if (traceInfo != null) {
                if (msgBloodPressure.getTime() - traceInfo.getTimeBloodPressure() > timeIntervalBloodPressure) {
                    traceInfo.setTimeBloodPressure(msgBloodPressure.getTime());
                    logger.trace("post msgBloodPressure: {}", msgBloodPressure);
                    eventBus.post(msgBloodPressure);
                } else {
                    logger.trace("ignore msgBloodPressure: {}", msgBloodPressure);
                }
            } else {
                CardEntity cardEntity = cardService.getCardByCardNumber(msgBloodPressure.getCardNumber());
                if (cardEntity != null) {
                    CardTraceInfo info = new CardTraceInfo(cardEntity.getCardType(), cardEntity.getCardNumber(), cardEntity.getSn());
                    info.setTimeBloodPressure(msgBloodPressure.getTime());
                    cardTraceMap.put(msgBloodPressure.getCardNumber(), info);
                    logger.trace("first message, post msgBloodPressure: {}", msgBloodPressure);
                    eventBus.post(msgBloodPressure);
                }
            }
        }
    }

    private class CardTraceInfo {
        private Integer cardType;
        private Long cardNumber;
        private String sn;
        private Integer locatorNumber = 0;
        private Point pos;
        private Integer floorNumber;
        private Integer lowpowerStatus;
        private Integer cutoffStatus;
        private Long timeLocate = 0L;
        private Long timeLocateActive = 0L;
        private Long timeCut = 0L;
        private Long timeKeepalive = 0L;
        private Long timeHeartRate = 0L;
        private Long timeBattery = 0L;
        private Long timeTemperature = 0L;
        private Long timeBloodPressure = 0L;
        private Long timeStepTrack = 0L;
        private AtomicBoolean inActiveLocator = new AtomicBoolean(false);
        private Long timeInActiveLocator = 0L;

        public CardTraceInfo(Integer cardType, Long cardNumber, String sn) {
            this.cardType = cardType;
            this.cardNumber = cardNumber;
            this.sn = sn;
        }

        public Integer getCardType() {
            return cardType;
        }

        public void setCardType(Integer cardType) {
            this.cardType = cardType;
        }

        public Long getCardNumber() {
            return cardNumber;
        }

        public void setCardNumber(Long cardNumber) {
            this.cardNumber = cardNumber;
        }

        public String getSn() {
            return sn;
        }

        public void setSn(String sn) {
            this.sn = sn;
        }

        public Integer getLocatorNumber() {
            return locatorNumber;
        }

        public void setLocatorNumber(Integer locatorNumber) {
            this.locatorNumber = locatorNumber;
        }

        public Point getPos() {
            return pos;
        }

        public void setPos(Point pos) {
            this.pos = pos;
        }

        public Integer getFloorNumber() {
            return floorNumber;
        }

        public void setFloorNumber(Integer floorNumber) {
            this.floorNumber = floorNumber;
        }

        public Integer getLowpowerStatus() {
            return lowpowerStatus;
        }

        public void setLowpowerStatus(Integer lowpowerStatus) {
            this.lowpowerStatus = lowpowerStatus;
        }

        public Integer getCutoffStatus() {
            return cutoffStatus;
        }

        public void setCutoffStatus(Integer cutoffStatus) {
            this.cutoffStatus = cutoffStatus;
        }

        public Long getTimeLocate() {
            return timeLocate;
        }

        public void setTimeLocate(Long timeLocate) {
            this.timeLocate = timeLocate;
        }

        public Long getTimeLocateActive() {
            return timeLocateActive;
        }

        public void setTimeLocateActive(Long timeLocateActive) {
            this.timeLocateActive = timeLocateActive;
        }

        public Long getTimeCut() {
            return timeCut;
        }

        public void setTimeCut(Long timeCut) {
            this.timeCut = timeCut;
        }

        public Long getTimeKeepalive() {
            return timeKeepalive;
        }

        public void setTimeKeepalive(Long timeKeepalive) {
            this.timeKeepalive = timeKeepalive;
        }

        public Long getTimeHeartRate() {
            return timeHeartRate;
        }

        public void setTimeHeartRate(Long timeHeartRate) {
            this.timeHeartRate = timeHeartRate;
        }

        public Long getTimeBattery() {
            return timeBattery;
        }

        public void setTimeBattery(Long timeBattery) {
            this.timeBattery = timeBattery;
        }

        public Long getTimeTemperature() {
            return timeTemperature;
        }

        public void setTimeTemperature(Long timeTemperature) {
            this.timeTemperature = timeTemperature;
        }

        public Long getTimeBloodPressure() {
            return timeBloodPressure;
        }

        public void setTimeBloodPressure(Long timeBloodPressure) {
            this.timeBloodPressure = timeBloodPressure;
        }

        public Long getTimeStepTrack() {
            return timeStepTrack;
        }

        public void setTimeStepTrack(Long timeStepTrack) {
            this.timeStepTrack = timeStepTrack;
        }

        public boolean isInActiveLocator() {
            return inActiveLocator.get();
        }

        public void setInActiveLocator(boolean inActiveLocator) {
            this.inActiveLocator.set(inActiveLocator);
        }

        public Long getTimeInActiveLocator() {
            return timeInActiveLocator;
        }

        public void setTimeInActiveLocator(Long timeInActiveLocator) {
            this.timeInActiveLocator = timeInActiveLocator;
        }
    }
}
